﻿using IOA.MES.Client.Common;
using IOA.MES.Client.Models.Response;
using IOA.MES.Client.Settings;
using IOA.MES.Common;
using NLog;
using Seagull.BarTender.Print;
using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Diagnostics;
using System.Reflection;
using IOA.MES.Client.Common.SocketUtils;
using System.Windows.Media;
using System.Text;

namespace IOA.MES.Client.NameplatePrinting
{
    /// <summary>
    /// NameplatePrintingIndex.xaml 的交互逻辑
    /// </summary>
    public partial class NameplatePrintingIndex : System.Windows.Window
    {
        private string preBarCode = "";
        private DateTime preBarTime = DateTime.MinValue;
        private List<ViaSiteRecord> records { get; set; } = new List<ViaSiteRecord>();
        private int downloadStatus = 1;//0:下载中，1:下载成功，2:下载失败、
        private List<Models.Response.Label> labels = new List<Models.Response.Label>();
        private SocketClient socketClient;
        private NameplateTip nameplateTip;
        private Dictionary<string, string> dictPrinters = new Dictionary<string, string>
        {
            { "边框条码", BaseEnv.GetStorage("边框条码") },
            { "电流标签", BaseEnv.GetStorage("电流标签") },
            { "能源标签", BaseEnv.GetStorage("能源标签") },
            { "铭牌", BaseEnv.GetStorage("铭牌") }
        };

        public NameplatePrintingIndex()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            txtTrueName.Content = BaseEnv.UserInfo.TrueName;
            InitDuties();
            InitMachines();
            InitRecords();
            TryConnectTCP();

            InitForms();
            nameplateTip = new NameplateTip();
            nameplateTip.Show();
        }

        #region 初始化数据
        public void InitDuties()
        {
            var duties = BaseEnv.InvokeApi<QueryDutiesResponse>("/api/Auth/QueryDuties", new { WorkshopCode = BaseEnv.WorkshopCode }).Data.Duties;

            cbDuties.ItemsSource = duties;
            cbDuties.DisplayMemberPath = "DutyName";
            cbDuties.SelectedValuePath = "DutyId";

            if (duties.Any())
            {
                cbDuties.SelectedIndex = 0;
            }
        }

        public void InitMachines()
        {
            var machines = BaseEnv.InvokeApi<QueryMachinesResponse>("/api/Machine/QueryMachines", new { WorkshopCode = BaseEnv.WorkshopCode, MachineType = (int)MachineType.NameplatePrinting }).Data.Machines;
            cbMachines.ItemsSource = machines;
            cbMachines.DisplayMemberPath = "MachineName";
            cbMachines.SelectedValuePath = "MachineId";

            if (machines.Any(_ => _.MachineId == BaseEnv.MachineId))
            {
                cbMachines.SelectedIndex = machines.FindIndex(_ => _.MachineId == BaseEnv.MachineId);
            }
            else
            {
                CommonMessage.Alert(this, "请先在系统设置中重新选择设备\r\nPlease reselect the device in the system settings now");
                new SettingsIndex().ShowDialog();
            }
        }

        private void InitRecords()
        {
            new TaskFactory().StartNew(() =>
            {
                Thread.Sleep(100);
                Dispatcher.Invoke(new Action(() =>
                {
                    var response = BaseEnv.InvokeApi<QueryViaSiteRecordsResponse>("/api/Machine/QueryViaSiteRecords", new { DutyId = Convert.ToInt32(cbDuties.SelectedValue), SiteType = SiteType.NameplatePrinting, MachineId = Convert.ToInt32(cbMachines.SelectedValue) });
                    if (response.ErrCode != 200)
                    {
                        CommonMessage.Alert(this, response.ErrMsg);
                        return;
                    }

                    records.Clear();
                    records.AddRange(response.Data.Records);
                    records.ForEach(_ => _.No = records.Count - records.IndexOf(_));
                    BindGridRecords();
                }));
            });
        }

        private void BindGridRecords()
        {
            gridRecords.ItemsSource = null;
            gridRecords.ItemsSource = records;
            lbTotal.Content = records.Select(_ => _.Code.ToUpper().Trim()).Distinct().Count();
        }

        private void TryConnectTCP()
        {
            var ipAddress = BaseEnv.GetStorage("DeviceIpAddress") ?? string.Empty;
            var port = BaseEnv.GetStorage("DevicePort") ?? string.Empty;
            if (!string.IsNullOrWhiteSpace(ipAddress) && !string.IsNullOrWhiteSpace(port))
            {
                socketClient = new SocketClient(this, ipAddress, Convert.ToInt32(port), OnTcpStatusChange, OnDataReceived, new List<byte> { }, 10000);
                socketClient.Connect();
            }
        }
        #endregion

        private void cb_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            InitRecords();
        }

        public void OnTcpStatusChange(bool connected)
        {
            if (connected)
            {
                lbStatus.Content = "已连接";
                lbStatus.Foreground = new SolidColorBrush(Colors.Green);
            }
            else
            {
                lbStatus.Content = "已断开";
                lbStatus.Foreground = new SolidColorBrush(Colors.Red);
            }
        }

        public void OnDataReceived(List<byte> data)
        {
            var barCode = Encoding.ASCII.GetString(data.ToArray())?.Trim();
            if (string.Equals(barCode.Trim(), "NR", StringComparison.CurrentCultureIgnoreCase))
            {
                return;
            }

            Dispatcher.BeginInvoke(new Action(() =>
            {
                txtCode.Text = barCode;
                txtCode_KeyUp(null, null);
            }));
        }

        private void txtCode_KeyUp(object sender, KeyEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtCode.Text.Trim()) || e != null && e.Key != Key.Enter)
            {
                CommonMessage.Log(LogLevel.Info, $"接收条码：{txtCode.Text.ToString()}");
                return;
            }
            else if (!string.IsNullOrWhiteSpace(preBarCode) && (DateTime.Now - preBarTime).TotalSeconds < 5
                && string.Equals(preBarCode, txtCode.Text.Trim(), StringComparison.CurrentCultureIgnoreCase))
            {
                CommonMessage.Log(LogLevel.Info, $"Ignore Code In 5 Seconds：{txtCode.Text.ToString()}");
                return;
            }
            preBarCode = txtCode.Text.Trim();
            preBarTime = DateTime.Now;
            CommonMessage.Log(LogLevel.Info, $"执行条码：{txtCode.Text.ToString()}");

            new TaskFactory().StartNew(() =>
            {
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    ViaSite();
                }));
            });
        }

        private void ViaSite(bool forceViaSite = false)
        {
            var getWorkOrderLabelsResponse = BaseEnv.InvokeApi<GetWorkOrderLabelsResponse>("/api/Machine/GetWorkOrderLabels", new
            {
                BarCode = txtCode.Text.Trim()
            });
            if (getWorkOrderLabelsResponse.ErrCode != 200)
            {
                CommonMessage.Alert(this, getWorkOrderLabelsResponse.ErrMsg);
                InitForms();
                return;
            }
            else
            {
                labels = getWorkOrderLabelsResponse.Data.Labels;
                gridLabels.RowDefinitions.Clear();
                gridLabels.Children.Clear();
                foreach (var label in getWorkOrderLabelsResponse.Data.Labels)
                {
                    var row = new RowDefinition();
                    row.Height = new GridLength(40);
                    var checkBox = new CheckBox();
                    checkBox.Margin = new Thickness(30, 0, 0, 0);
                    checkBox.Content = label.LabelName;
                    checkBox.IsChecked = true;
                    checkBox.FontSize = 15;
                    checkBox.VerticalAlignment = VerticalAlignment.Center;
                    checkBox.SetValue(Grid.RowProperty, getWorkOrderLabelsResponse.Data.Labels.IndexOf(label));
                    gridLabels.RowDefinitions.Add(row);
                    gridLabels.Children.Add(checkBox);
                }

                DownloadLabels(getWorkOrderLabelsResponse.Data.Labels);
            }

            //标签未下载成功
            if (downloadStatus != 1)
            {
                return;
            }

            var response = BaseEnv.InvokeApi<ViaSiteResponse>("/api/Machine/ViaSite", new
            {
                SiteType = SiteType.NameplatePrinting,
                DutyId = Convert.ToInt32(cbDuties.SelectedValue),
                ForceViaSite = forceViaSite,
                MachineId = Convert.ToInt32(cbMachines.SelectedValue),
                Code = txtCode.Text.Trim()
            });
            if (response.ErrCode != 200)
            {
                mediaElResult.Source = new Uri($"{BaseEnv.LocalDirectory}\\res\\audio\\Fail.wav");
                mediaElResult.Play();

                if (response.ErrCode == 110032)//重复打印判断
                {
                    if (CommonMessage.Confirm(this, response.ErrMsg))
                    {
                        ViaSite(true);
                    }
                    else
                    {
                        InitForms();
                    }
                    return;
                }

                CommonMessage.Alert(this, response.ErrMsg);
                InitForms();
                return;
            }
            CommonMessage.Log(LogLevel.Info, $"过站成功：{txtCode.Text.Trim()}");

            mediaElResult.Source = new Uri($"{BaseEnv.LocalDirectory}\\res\\audio\\Success.wav");
            mediaElResult.Play();

            txtWorkOrderNo.Text = response.Data.ViaSiteRecord.WorkOrderNo;

            if (response.Data.DutyId != Convert.ToInt32(cbDuties.SelectedValue))
            {
                cbDuties.SelectedValue = response.Data.DutyId;
            }
            else
            {
                response.Data.ViaSiteRecord.No = records.Count + 1;
                records.Insert(0, response.Data.ViaSiteRecord);
                BindGridRecords();
            }

            InitForms();

            if (getWorkOrderLabelsResponse.Data.Labels.Any())
            {
                SetTipData(getWorkOrderLabelsResponse.Data.Labels);
                PrintLabels(getWorkOrderLabelsResponse.Data.Labels);
            }
        }

        private void SetTipData(List<Models.Response.Label> labels)
        {
            try
            {
                var data = labels.FirstOrDefault(_ => string.Equals(_.LabelName, "边框条码", StringComparison.CurrentCultureIgnoreCase))?.LabelData
                ?? new List<KeyValuePair<string, string>>();
                if (!data.Any())
                {
                    data = labels.FirstOrDefault(_ => string.Equals(_.LabelName, "铭牌", StringComparison.CurrentCultureIgnoreCase))?.LabelData
                        ?? new List<KeyValuePair<string, string>>();
                }
                if (!data.Any())
                {
                    return;
                }
                nameplateTip.SetData(data);
            }
            catch (Exception ex)
            {
                CommonMessage.Log(LogLevel.Warn, $"设置弹窗数据异常：{ex.Message}", ex);
            }
        }

        private void PrintLabels(List<Models.Response.Label> labels)
        {
            var engine = new Engine(true);
            try
            {
                foreach (var label in labels)
                {
                    if (!dictPrinters.ContainsKey(label.LabelName) || string.IsNullOrWhiteSpace(dictPrinters[label.LabelName]))
                    {
                        continue;
                    }
                    var btw = $"{BaseEnv.LocalDirectory}\\data\\{label.LabelFile.Substring(label.LabelFile.LastIndexOf("/") + 1)}";
                    var keys = label.LabelData.Select(_ => _.Key).ToList();
                    var values = label.LabelData.Select(_ => $"'{_.Value}'").ToList();
                    var sql = $"({string.Join(", ", keys)}) VALUES ({string.Join(", ", values)})";
                    if (!new[] { "铭牌", "边框条码", "电流标签", "能源标签" }.Contains(label.LabelName, StringComparer.CurrentCultureIgnoreCase))
                    {
                        continue;
                    }
                    ExcuteSql($"DELETE FROM {label.TableName}");
                    ExcuteSql($"INSERT INTO {label.TableName} {sql}");

                    var format = !engine.Documents.Any(_ => string.Equals(_.FileName, btw, StringComparison.CurrentCultureIgnoreCase)) ? engine.Documents.Open(btw) :
                        engine.Documents.FirstOrDefault(_ => string.Equals(_.FileName, btw, StringComparison.CurrentCultureIgnoreCase));
                    try
                    {
                        if (format.PrintSetup.SupportsIdenticalCopies)
                        {
                            format.PrintSetup.IdenticalCopiesOfLabel = 1;
                        }

                        format.PrintSetup.PrinterName = dictPrinters[label.LabelName];
                        int waitForCompletionTimeout = 10000;//10秒
                        Messages messages;
                        var result = format.Print($"PrintCodes_{DateTime.Now.ToLongDateString()}", waitForCompletionTimeout, out messages);
                        var msgs = new List<string>();
                        foreach (var msg in messages)
                        {
                            msgs.Add(msg.Text);
                        }
                        CommonMessage.Log(LogLevel.Info, string.Join("\r\n", msgs));
                    }
                    catch (Exception ex)
                    {
                        CommonMessage.Alert(this, $"标签打印出错，请重新尝试：{ex.Message}");
                        CommonMessage.Log(LogLevel.Fatal, $"标签打印出错：{ex.Message}", ex);
                    }
                    finally
                    {
                        try
                        {
                            format.Close(SaveOptions.DoNotSaveChanges);
                        }
                        catch (Exception ex)
                        {
                            CommonMessage.Log(LogLevel.Fatal, $"format.Close异常：{ex.Message}", ex);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                CommonMessage.Alert(this, $"标签打印异常：{ex.ToString()}");
            }
            finally
            {
                engine.Dispose();
            }
        }

        private void InitForms()
        {
            txtCode.Text = "";
            txtCode.Focus();
        }

        private void DownloadLabels(List<Models.Response.Label> labels)
        {
            this.downloadStatus = 0;
            SetDownloadStatus();

            var btwFolder = $@"{BaseEnv.LocalDirectory}\data";
            if (!Directory.Exists(btwFolder))
            {
                Directory.CreateDirectory(btwFolder);
            }
            for (var i = 0; i < labels.Count; i++)
            {
                try
                {
                    var fileName = labels[i].LabelFile.Substring(labels[i].LabelFile.LastIndexOf("/") + 1);
                    var filePath = $@"{btwFolder}\{fileName}";
                    if (!File.Exists(filePath))
                    {
                        new FtpUtils(BaseEnv.UserInfo.FtpConfig.UserName, BaseEnv.UserInfo.FtpConfig.Password).Download(labels[i].LabelFile, filePath);
                    }
                }
                catch (Exception ex)
                {
                    CommonMessage.Alert(this, $"标签文件下载失败\r\nLabel file download failed：\r\n{labels[i].LabelName}");
                    downloadStatus = 2;
                    SetDownloadStatus();
                    return;
                }
            }
            downloadStatus = 1;
            SetDownloadStatus();
        }

        private void SetDownloadStatus()
        {
            lbDownloading.Visibility = Visibility.Hidden;
            lbFailed.Visibility = Visibility.Hidden;
            if (downloadStatus == 0)
            {
                lbDownloading.Visibility = Visibility.Visible;
            }
            else if (downloadStatus == 2)
            {
                lbFailed.Visibility = Visibility.Visible;
            }
        }

        private void Menu_Click(object sender, RoutedEventArgs e)
        {
            switch (((MenuItem)sender).Name)
            {
                case "btnSettings":
                    new SettingsIndex().ShowDialog();
                    break;
                case "btnDeviceSettings":
                    if (new WinDeviceSettings().ShowDialog() == true)
                    {
                        TryConnectTCP();
                    }
                    break;
                case "btnPrinterSettings":
                    new PrinterSetting().ShowDialog();
                    dictPrinters = new Dictionary<string, string>
                    {
                        { "边框条码", BaseEnv.GetStorage("边框条码") },
                        { "电流标签", BaseEnv.GetStorage("电流标签") },
                        { "能源标签", BaseEnv.GetStorage("能源标签") },
                        { "铭牌", BaseEnv.GetStorage("铭牌") }
                    };
                    break;
                case "btnNameplatePreview":
                    if (!BaseEnv.UserInfo.Roles.Any(_ => new[] { 1, 15 }.Contains(_.RoleId)))
                    {
                        CommonMessage.Alert(this, "只有“车间工艺”可以预览标签");
                        return;
                    }
                    new NameplatePreview().ShowDialog();
                    break;
                case "btnMissingRecords":
                    new MissingSiteRecord(Convert.ToInt32(cbMachines.SelectedValue)).Show();
                    break;
                case "btnLogout":
                    new LoginWindow(false).Show();
                    this.Hide();
                    break;
                case "btnAbout":
                    MessageBox.Show($"AISUNMes Product Version:{FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion}");
                    break;
            }
        }

        private void ExcuteSql(string sql)
        {
            string strConn = $@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={BaseEnv.LocalDirectory}\\data\\data.mdb";
            var myConn = new OleDbConnection(strConn);
            try
            {
                myConn.Open();
                var inst = new OleDbCommand(sql, myConn);
                inst.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                CommonMessage.Alert(this, $"执行SQL异常，请重新尝试：{ex.Message}");
                CommonMessage.Log(LogLevel.Fatal, $"执行SQL异常：{ex.Message}", ex);
            }
            if (myConn.State != System.Data.ConnectionState.Closed)
            {
                myConn.Close();
            }
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            if (nameplateTip != null && PresentationSource.FromVisual(nameplateTip) != null)
            {
                nameplateTip.Close();
            }
            Environment.Exit(0);
        }
    }
}
